﻿using KochamPycze.Model;

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.TextFormatting;

namespace KochamPycze.GUI
{
    public class NoteGlyph
    {
        private Note note;

        public NoteGlyph(Note note)
        {
            this.note = note;
        }

        private static int X=200;

        private void DrawNote(DrawingGroup scene, int index)
        {
            DrawingGroup noteframe = new DrawingGroup();
            ImageDrawing noteImg = new ImageDrawing();
            noteImg.ImageSource = notes[index];

            noteframe.Children.Add(noteImg);
            if (note.value < threshold)
            {
                noteImg.Rect = new Rect(X, normal_base - step * note.position, noteWidth, noteHeight);
            }
            else
            {
                noteImg.Rect = new Rect(X, inverted_base + step * note.position, noteWidth, noteHeight);
                noteframe.Transform = new ScaleTransform(1, -1);
            }
  
            scene.Children.Add(noteframe);
        }

        private void DrawSharp(DrawingGroup scene, int index)
        {
            ImageDrawing sharpImg = new ImageDrawing();
            sharpImg.ImageSource = sharpes[index];

            if (note.value < threshold)
                sharpImg.Rect = new Rect(X - sharpWidth, normal_base + noteHeight - sharpHeight - step * note.position, sharpWidth, sharpHeight);
            else
                sharpImg.Rect = new Rect(X - sharpWidth, normal_base + 1.6 * sharpHeight - step * note.position, sharpWidth, sharpHeight);
            scene.Children.Add(sharpImg);
        }

        private void DrawName(DrawingGroup scene, int index)
        {
            DrawingGroup textframe = new DrawingGroup();
            GlyphRunDrawing text = new GlyphRunDrawing(textBrushes[index], names[note.value % octave_semitones]);

            textframe.Children.Add(text);

            if (note.value < threshold)
                textframe.Transform = new TranslateTransform(X, upper_text);
            else
                textframe.Transform = new TranslateTransform(X, lower_text);
 
            scene.Children.Add(textframe);
        }

        private void DrawLine(DrawingGroup scene, double y)
        {
            ImageDrawing img = new ImageDrawing();
            img.ImageSource = bar;
            img.Rect = new Rect(X-sharpWidth-5, y, bar.Width, bar.Height);
            scene.Children.Add(img);
        }

        private void DrawLowerLines(DrawingGroup scene, int amount)
        {
            double self_base = normal_base - bar.Height + 4*step;
            double self_step = 2 * step;
            for (int i = 0; i < amount; ++i)
                DrawLine(scene, self_base + i*self_step);
        }

        private void DrawUpperLines(DrawingGroup scene, int amount)
        {
            double self_base=normal_base-8*step-bar.Height;
            double self_step = step * 2;
            for (int i = 0; i < amount; ++i)
                DrawLine(scene, self_base - i * self_step);
        }

        public void Draw(DrawingGroup scene)
        {
            if (note.color == Note.Color.None) return;
            X += 100;
            try
            {
                int index = (int)note.color;
                DrawLowerLines(scene, (5 - note.position) / 2);
                DrawUpperLines(scene, (note.position - 13) / 2);
                DrawNote(scene,index);
                if (note.sharp) DrawSharp(scene, index);
                DrawName(scene,index);
            }
            catch (Exception e) { e.Handle(); }
        }

        private static readonly int[] positions = { 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6 };
        private static readonly bool[] has_sharp = { false, false, true, false, true, false, false, true, false, true, false, true };
        private static readonly GlyphRun[] names;
        private static readonly BitmapImage[] notes;
        private static readonly BitmapImage[] sharpes;
        private static readonly BitmapImage bar;
        private static readonly double noteWidth, noteHeight;
        private static readonly double sharpWidth, sharpHeight;
        private static readonly int threshold = 18; //f
        private static readonly double step = 12.2;
        private static readonly int octave_semitones = 12;
        private static readonly Brush[] textBrushes;
        private static readonly double normal_base = 208;
        private static readonly double inverted_base = -376;
        private static readonly double upper_text = 100;
        private static readonly double lower_text = 320;

        private static BitmapImage LoadImage(string name)
        {
            BitmapImage img = null;
            try
            {
                img = new BitmapImage(new Uri(name, UriKind.Relative));
                double k = img.Width;
            }
            catch (Exception e) { e.Handle(); }

            return img;
        }

        //I could not cut it into peces because of readonly
        static NoteGlyph()
        {
            double DesiredNoteHeight = 100;
            double DesiredSharpHeight = 36;
            try
            {
                bar = LoadImage("Bar.png");

                notes = new BitmapImage[5];
                notes.SetValue(null, 0);
                notes.SetValue(LoadImage("NoteBlack.png"), 1);
                notes.SetValue(LoadImage("NoteRed.png"), 2);
                notes.SetValue(LoadImage("NoteGreen.png"), 3);
                notes.SetValue(LoadImage("NoteBlue.png"), 4);

                noteHeight = notes[1].Height;
                noteWidth = notes[1].Width / noteHeight * DesiredNoteHeight;
                noteHeight = DesiredNoteHeight;

                sharpes = new BitmapImage[5];
                sharpes.SetValue(null, 0);
                sharpes.SetValue(LoadImage("SharpBlack.png"), 1);
                sharpes.SetValue(LoadImage("SharpRed.png"), 2);
                sharpes.SetValue(LoadImage("SharpGreen.png"), 3);
                sharpes.SetValue(LoadImage("SharpBlue.png"), 4);

                sharpHeight = sharpes[1].Height;
                sharpWidth = sharpes[1].Width / sharpHeight * DesiredSharpHeight;
                sharpHeight = DesiredSharpHeight;

                //                  B   C   C#  D   D#  E  F    F#  G  G#  A    A#
                double[] width = { 32, 36, 36, 40, 40, 32, 32, 32, 38, 38, 32, 32 };
                ushort[] __l = { 37, 38, 38, 39, 39, 40, 41, 41, 42, 42, 36, 36 };
                ushort[] __s = { 2, 2, 6, 2, 6, 2, 2, 6, 2, 6, 2, 6 };

                GlyphTypeface font = new GlyphTypeface(new Uri(@"C:\WINDOWS\Fonts\GOTHICI.TTF"));
                names = new GlyphRun[12];

                for (ushort i = 0; i < 12; ++i)
                {
                    GlyphRun mark = new GlyphRun(font, 0, false, 64,
                        new ushort[] { __l[i], __s[i] },
                        new Point(0, 0),
                        new double[] { width[i], 32 },
                        null, null, null, null, null, null);
                    names.SetValue(mark, i);
                }

                textBrushes = new Brush[5];
                textBrushes.SetValue(null, 0);
                textBrushes.SetValue(new SolidColorBrush(System.Windows.Media.Color.FromRgb(0, 0, 0)), 1);
                textBrushes.SetValue(new SolidColorBrush(System.Windows.Media.Color.FromRgb(179, 35, 35)), 2);
                textBrushes.SetValue(new SolidColorBrush(System.Windows.Media.Color.FromRgb(0, 185, 0)), 3);
                textBrushes.SetValue(new SolidColorBrush(System.Windows.Media.Color.FromRgb(0, 87, 212)), 4);
            }
            catch (Exception e) { e.Handle(); }
        }
    }
}
